using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using LeisureCenter.Api;

namespace LeisureCenter.MenuItems
{
    public class RemovableMediaMenuItem : FileSystemMenuItem
    {
        public RemovableMediaMenuItem(string volumeLabel, string path, string iconName)
            : base(volumeLabel, path, iconName)
	    {
	    }
    }

    public class VideoDvdMenuItem : IMenuItem
    {
        private string path;
        private string volumeLabel;

        public VideoDvdMenuItem(string volumeLabel, string path)
        {
            this.volumeLabel = volumeLabel;
            this.path = path;
        }

        #region IMenuItem Membres

        public string Text { get { return @"Video DVD " + path + Environment.NewLine + volumeLabel; } }

        public string IconName { get { return "dvdvideo"; } }

        public void Execute()
        {
            ExecuteAgain();
        }

        public void ExecuteAgain()
        {
            Program.LeisureCenterInstance.PlaylistManager.OpenVideoDvd(path + @"VIDEO_TS\VIDEO_TS.IFO");
        }

        public void OptionsExecute()
        {
        }

        #endregion
    }

    public class AudioCdMenuItem : IMenuItem
    {
        private string path;

        public AudioCdMenuItem(string path)
        {
            this.path = path;
        }

        #region IMenuItem Membres

        public string Text { get { return @"Audio CD " + path; } }

        public string IconName { get { return "audiocd"; } }

        public void Execute()
        {
            ExecuteAgain();
        }

        public void ExecuteAgain()
        {
            Program.LeisureCenterInstance.MenuManager.FillSubmenu(null);
            Program.LeisureCenterInstance.BrowserManager.Browse(null);
            Program.LeisureCenterInstance.PlaylistManager.OpenAudioCd(path);
            Program.LeisureCenterInstance.MainForm.FocusPlaylist();
        }

        public void OptionsExecute()
        {
        }

        #endregion
    }

    internal enum ShellChangeNotifyFlag
    {
        IDList = 0x0000,
        AnsiPath = 0x0001,
        AnsiPrinter = 0x0002,
        DWord = 0x0003,
        WidePath = 0x0005,
        WidePrinter = 0x0006,
        Type = 0x00FF,
        Flush = 0x1000,
        FlushNoWait = 0x2000
    }

    internal enum SHCNE : uint
    {
        SHCNE_RENAMEITEM = 0x00000001,
        SHCNE_CREATE = 0x00000002,
        SHCNE_DELETE = 0x00000004,
        SHCNE_MKDIR = 0x00000008,
        SHCNE_RMDIR = 0x00000010,
        SHCNE_MEDIAINSERTED = 0x00000020,
        SHCNE_MEDIAREMOVED = 0x00000040,
        SHCNE_DRIVEREMOVED = 0x00000080,
        SHCNE_DRIVEADD = 0x00000100,
        SHCNE_NETSHARE = 0x00000200,
        SHCNE_NETUNSHARE = 0x00000400,
        SHCNE_ATTRIBUTES = 0x00000800,
        SHCNE_UPDATEDIR = 0x00001000,
        SHCNE_UPDATEITEM = 0x00002000,
        SHCNE_SERVERDISCONNECT = 0x00004000,
        SHCNE_UPDATEIMAGE = 0x00008000,
        SHCNE_DRIVEADDGUI = 0x00010000,
        SHCNE_RENAMEFOLDER = 0x00020000,
        SHCNE_FREESPACE = 0x00040000,
        SHCNE_EXTENDED_EVENT = 0x04000000,
        SHCNE_ASSOCCHANGED = 0x08000000,
        SHCNE_DISKEVENTS = 0x0002381F,
        SHCNE_GLOBALEVENTS = 0x0C0581E0,
        SHCNE_ALLEVENTS = 0x7FFFFFFF,
        SHCNE_INTERRUPT = 0x80000000,
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    internal struct SHChangeNotifyEntry
    {
        public IntPtr pIdl;
        [MarshalAs(UnmanagedType.Bool)]
        public Boolean Recursively;
    }

    public class RemovableMediasMainMenuItemsProvider : Control, IMainMenuItemsProvider
    {
        List<IMenuItem> items;

        private void RefreshItems()
        {
            items = new List<IMenuItem>();

            // drives
            foreach (DriveInfo driveInfo in DriveInfo.GetDrives())
            {
                if (!driveInfo.Name.StartsWith("A", StringComparison.OrdinalIgnoreCase)
                    && !driveInfo.Name.StartsWith("B", StringComparison.OrdinalIgnoreCase)
                    && (driveInfo.DriveType == DriveType.CDRom || driveInfo.DriveType == DriveType.Removable)
                    && driveInfo.IsReady)
                {
                    if (driveInfo.DriveType == DriveType.Removable)
                        items.Add(new RemovableMediaMenuItem(driveInfo.VolumeLabel, driveInfo.Name, "removablemedia"));
                    else
                    if (File.Exists(driveInfo.Name + @"VIDEO_TS\VIDEO_TS.IFO"))
                        items.Add(new VideoDvdMenuItem(driveInfo.VolumeLabel, driveInfo.Name));
                    else
                    if (driveInfo.VolumeLabel == "Audio CD")
                        items.Add(new AudioCdMenuItem(driveInfo.Name));
                    else
                        items.Add(new RemovableMediaMenuItem(driveInfo.VolumeLabel, driveInfo.Name, "folderdocuments"));
                }
            }
        }

        #region shell notifications helpers

        private uint notifyid;
        public const uint WM_SHNOTIFY = 0x0401;

        [DllImport("shell32.dll", EntryPoint = "#2", CharSet = CharSet.Auto)]
        private static extern uint SHChangeNotifyRegister(
            IntPtr hWnd,
            ShellChangeNotifyFlag fSources,
            SHCNE fEvents,
            uint wMsg,
            int cEntries,
            ref SHChangeNotifyEntry pFsne);

        [DllImport("shell32.dll", EntryPoint = "#4", CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern Boolean SHChangeNotifyUnregister(ulong hNotify);

        private void StartListening()
        {
            if (notifyid == 0)
            {
                SHChangeNotifyEntry entry = new SHChangeNotifyEntry();
                entry.pIdl = IntPtr.Zero;
                entry.Recursively = true;
                notifyid = SHChangeNotifyRegister(Handle, ShellChangeNotifyFlag.Type | ShellChangeNotifyFlag.IDList, SHCNE.SHCNE_MEDIAINSERTED | SHCNE.SHCNE_MEDIAREMOVED, WM_SHNOTIFY, 1, ref entry);
            }
        }

        private void StopListening()
        {
            if (notifyid != 0)
            {
                SHChangeNotifyUnregister(notifyid);
            }

        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg != WM_SHNOTIFY)
                base.WndProc(ref m);
            else
            {
                RefreshItems();
                Program.LeisureCenterInstance.MenuManager.RefreshMainMenu();
            }
        }

        #endregion

        public RemovableMediasMainMenuItemsProvider()
        {
            StartListening();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
                StopListening();
            base.Dispose(disposing);
        }

        #region IMainMenuItemsProvider Membres

        public IEnumerable<IMenuItem> Items
        {
            get 
            {
                if (items == null)
                    RefreshItems();
                return items;    
            }
        }

        #endregion
    }
}
